﻿using System.Net.Sockets;
using Google.Protobuf;
using MoonFramework.Tool;
using Serilog;

namespace MoonFramework.Net;

/// <summary>
///     网络连接基类，更加面向对象，方便功能拓展
///     职责：发送信息，关闭连接，断开回调，接收消息回调
/// </summary>
public class BaseConnection
{
    public Action<BaseConnection, byte[]> DataReceived;
    public Action<BaseConnection> DisConnected;

    public Socket Socket { get; private set; }

    public void Start(Socket socket)
    {
        //创建解码器
        SocketReceiver socketReceiver = new(socket);
        Socket = socket;
        socketReceiver.DataReceived += OnDataReceived;
        socketReceiver.Disconnected += OnDisConnected;
        socketReceiver.Start();
    }

    private void OnDisConnected()
    {
        DisConnected?.Invoke(this);
    }

    private void OnDataReceived(byte[] buffer)
    {
        //TODO:解包
        using (var buf = DataStream.Allocate(buffer))
        {
            //获取消息序列号
            var code = buf.ReadT<ushort>();
            ProtoTool.ParseFrom(code, buffer, 2, buffer.Length - 2);
            DataReceived?.Invoke(this, buffer);
        }
    }

    public void Close()
    {
        try
        {
            Socket.Shutdown(SocketShutdown.Both);
        }
        catch
        {
            //TODO:处理消息异常，日志回退等
        }

        Socket.Close();
        Socket = null;
        DisConnected?.Invoke(this);
    }

    #region 发送网络数据包

    public void Send(IMessage message)
    {
        //TODO:打包IMessage
        using (var buf = DataStream.Allocate())
        {
            var code = ProtoTool.ToCode(message.GetType());
            buf.WriteT(message.CalculateSize() + 2);
            buf.WriteT((ushort)code);
            message.WriteTo(buf);
            Send(buf.ToArray(), 0, buf.ToArray().Length);
        }
    }

    public void Send(byte[] data, int offset, int count)
    {
        lock (this)
        {
            if (Socket.Connected)
            {
                SocketAsyncEventArgs args = new();
                args.SetBuffer(data, offset, count);
                args.Completed += ArgsOnCompleted;
                Socket.SendAsync(args);
            }
        }
    }

    private void ArgsOnCompleted(object? sender, SocketAsyncEventArgs e)
    {
        //TODO:发送成功的完成事件
        //释放内存
        e.SetBuffer(null, 0, 0);
        Log.Debug("成功发送了一条消息");
    }

    #endregion
}